package com.md.client.helper;

import com.md.base.exception.ServerException;
import com.md.client.OpenApiClient;
import com.md.config.Logs;
import com.md.model.system.CommonResult;
import com.md.request.GenerateTokenRequest;
import com.md.response.AppInfoResponse;
import com.md.response.GenerateTokenResponse;
import com.md.response.ReplacementTokenResponse;
import com.md.util.EncryptionUtils;
import com.md.util.ObjectUtil;
import com.md.util.RedisUtil;
import com.md.util.SpringContextUtil;
import com.md.util.StringUtil;
import com.md.value.ModuleConstants;
import com.md.value.OauthConstants;
import com.md.value.enums.ErrorEnum;
import com.md.value.enums.OperationEnum;
import com.md.value.server.ServerContext;
import io.swagger.annotations.Api;
import io.vavr.control.Try;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@RestController
@Api
@RequiredArgsConstructor
public class TokenClient {
  private static final String PATH_PREFIX = "/oauth";
  private final RedisUtil redisUtil;

  @PostMapping(PATH_PREFIX + "/token")
  @Logs(title = "生成token", operation = OperationEnum.SELECT)
  public CommonResult<GenerateTokenResponse> generateToken(@RequestBody final GenerateTokenRequest request) {
    GenerateTokenResponse response = new GenerateTokenResponse();
    try {
      Optional<TokenAfter> tokenAfterBean = Optional.ofNullable(Try.of(() ->
        SpringContextUtil.getBean(TokenAfter.class)).getOrElse(() -> null));
      AppInfoResponse appInfoResponse = OpenApiClient.queryAppInfo(request.getTenantId(), request.getBrandId());
      if (ObjectUtil.isEmpty(appInfoResponse)) {
        throw ServerException.build(ErrorEnum.SYSTEM_ERROR);
      }
      Number expireTime = appInfoResponse.getExtraValue(ModuleConstants.EXPIRE_TIME);
      TimeUnit timeUnit = TimeUnit.valueOf(appInfoResponse.getExtraValue(ModuleConstants.TIME_UNIT));
      ReplacementTokenResponse jsonEntity = new ReplacementTokenResponse();
      jsonEntity.setUserId(request.getUserId());
      tokenAfterBean.ifPresent(tokenAfter -> jsonEntity.setExtra(tokenAfter.buildExtra(request)));
      jsonEntity.setTenantId(request.getTenantId());
      jsonEntity.setBrandId(request.getBrandId());
      String sub = StringUtil.objectToJson(jsonEntity);
      String originalToken = EncryptionUtils.jwtEncryption(sub, expireTime.longValue(), timeUnit);

      String uuid = UUID.randomUUID().toString();
      String shortToken = EncryptionUtils.jwtEncryption(uuid, expireTime.longValue(), timeUnit);

      response.setOriginalToken(originalToken);
      response.setShortToken(shortToken);
      redisUtil.set(OauthConstants.SHORT_TOKEN_KEY + "_" + uuid, originalToken, timeUnit, expireTime.longValue());
      tokenAfterBean.ifPresent(tokenAfter -> tokenAfter.exchange(response));
    } catch (Exception e) {
      throw ServerException.build(ErrorEnum.SYSTEM_ERROR, e);
    } finally {
      ServerContext.clear();
    }
    return CommonResult.success(response);
  }
}
